package task

import (
	"context"

	"github.com/beherochuling/beesoft_api/app/service/task/audio"
	"github.com/beherochuling/beesoft_api/app/service/task/document"
	"github.com/beherochuling/beesoft_api/app/service/task/image"
	"github.com/beherochuling/beesoft_api/app/service/task/other"
	"github.com/beherochuling/beesoft_api/app/service/task/text"
	"github.com/beherochuling/beesoft_api/app/service/task/video"

	"github.com/beherochuling/beesoft_api/app/dao"
	"github.com/beherochuling/beesoft_api/app/helper/software/software"
	model "github.com/beherochuling/beesoft_api/app/model/task"

	"github.com/google/uuid"

	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/frame/g"
)

var Task = &taskService{
	Text:     text.NewText(),
	Document: document.NewDocument(),
	Image:    image.NewImage(),
	// Visual:   visual{},
	Audio: audio.NewAudio(),
	Video: video.NewVideo(),
	Other: other.NewOther(),
}

type taskService struct {
	Text     *text.TextService
	Document *document.DocumentService
	Image    *image.ImageService
	Visual   *visualService
	Audio    *audio.AudioService
	Video    *video.VideoService
	Other    *other.OtherService
}

func (r *taskService) Create(ctx context.Context, taskType string, createdBy uint) (*model.Tasks, error) {
	task := &model.Tasks{
		Uuid:      uuid.New().String(),
		Type:      taskType,
		Status:    model.TaskStatusTodo,
		CreatedBy: createdBy,
	}

	var id int64
	var err error = nil
	id, err = dao.TaskTasks.Ctx(ctx).
		Data(task).
		InsertAndGetId()
	if err != nil {
		return nil, err
	}

	task.Id = uint(id)
	return task, nil
}
func (r *taskService) CreateExtend(ctx context.Context, taskExtend *model.TaskExtends) (*model.TaskExtends, error) {
	id, err := dao.TaskTasksExtend.Ctx(ctx).
		Data(taskExtend).
		InsertAndGetId()
	if err != nil {
		return nil, err
	}

	taskExtend.Id = uint(id)
	return taskExtend, nil
}
func (r *taskService) Update(ctx context.Context, taskId uint, data g.Map) {
	_, err := dao.TaskTasks.Ctx(ctx).
		Where(dao.TaskTasks.Columns().Id, taskId).
		Data(data).
		Update()

	if err != nil {
		// helper.Error("failed to update", err.Error())
	}

	return
}
func (r *taskService) UpdateExtend(ctx context.Context, taskId uint, data g.Map) {
	_, err := dao.TaskTasksExtend.Ctx(ctx).
		Where(dao.TaskTasksExtend.Columns().TaskId, taskId).
		Data(data).
		Update()

	if err != nil {
		// helper.Error("failed to update", err.Error())
	}

	return
}
func (*taskService) GetByID(ctx context.Context, id uint) (*model.Tasks, error) {
	task := &model.Tasks{}

	err := dao.TaskTasks.Ctx(ctx).Where(dao.TaskTasks.Columns().Id, id).Scan(task)
	if err != nil {
		return nil, err
	}

	return task, nil
}
func (*taskService) GetByUUID(ctx context.Context, uuid string) (*model.Tasks, error) {
	task := &model.Tasks{}

	err := dao.TaskTasks.Ctx(ctx).Where(dao.TaskTasks.Columns().Uuid, uuid).Scan(task)
	if err != nil {
		return nil, err
	}

	return task, nil
}
func (*taskService) GetExtendByID(ctx context.Context, id uint) (*model.TaskExtends, error) {
	taskExtend := &model.TaskExtends{}

	err := dao.TaskTasksExtend.Ctx(ctx).
		Where(dao.TaskTasksExtend.Columns().TaskId, id).
		Scan(taskExtend)
	if err != nil {
		return nil, err
	}

	return taskExtend, nil
}

func (r *taskService) Push(ctx context.Context, task *model.Tasks) error {
	queueName := getQueueName(task.Type)
	event := model.Event{
		// ID: task.Id,
		UUID: task.Uuid,
		Type: task.Type,
	}
	_, err := software.DoRedis(ctx, "lpush", queueName, event)
	if err != nil {
		// helper.Error("create push failed", err.Error())
	}

	return nil
}
func (r *taskService) Pop(ctx context.Context, taskType string) *model.Event {
	var event *model.Event

	queueName := getQueueName(taskType)
	data, err := software.DoRedis(ctx, "rpop", queueName)
	if err != nil {
		// helper.Error("consume pop failed", err.Error())
		return nil
	}

	if !data.IsEmpty() {
		err = data.Struct(&event)
		if err != nil {
			// helper.Error("consume struct failed", err.Error())
			return nil
		}
	}

	return event
}
func getQueueName(taskType string) string {
	return "queue/" + taskType
}

func (r *taskService) Run(ctx context.Context, event *model.Event) {
	// helper.Info("Run Main "+event.Type, event.UUID)

	task, err := r.GetByUUID(ctx, event.UUID)
	if err != nil || task.Id == 0 {
		// helper.Error("task is empty, err=", err, event.UUID)
		return
	}
	extend, err := r.GetExtendByID(ctx, task.Id)
	if err != nil || extend.Id == 0 {
		// helper.Error("extend is empty, err=", err, event.UUID)
		return
	}

	switch event.Type {
	case "docs/conversion":
		// Task.Document.Run(event)
	case "docs/ocr":
		// Task.Document.Run(event)
	case "image/backgroundremove":
		// Task.Image.Run(event)
	case "image/watermarkremove":
		// Task.Image.Run(event)
	case "other/archive":
		err = Task.Other.Archive.Run(event.UUID, extend)
	case "other/compress":
		// Task.Other.RunCompress(event)
	default:
	}

	if err != nil {
		// helper.Error("task failed", err.Error())
	} else {
		Task.Update(ctx, task.Id, g.Map{
			dao.TaskTasks.Columns().Status:      1,
			dao.TaskTasks.Columns().Progress:    100,
			dao.TaskTasks.Columns().CompletedAt: gdb.Raw("now()"),
		})
	}
}
